##################################################################
# File : /lua/formations.lua
# Description : Formations module
# Author : GPG
##################################################################

#
# Basic create formation scripts
#

SurfaceFormations = {
    'BlockFormation',
}

AirFormations = {
    'VFormation',
}

ComboFormations = {
    'BlockFormation',
}

local FormationPos = {} # list to be returned

function SimLog(...)
    if IsSim() then
        LOG(unpack(arg))
    end
end

function BlockFormation( formationUnits )
    local layout = {
        { category = categories.GIANT, width = 6, length = 6 },
        { category = categories.SOLDIER, width = 1, length = 1 },
        { category = categories.HERO, width = 4, length = 4 },
        { category = categories.PRIEST, width = 2, length = 2 },
        { category = categories.ARCHER, width = 1, length = 1 },
        { category = categories.ARTILLERY, width = 4, length = 4 },
        { category = categories.ALLUNITS, width = 4, length = 4, resetPosition = true },
    }

    for i,u in formationUnits do
        for k,cat in layout do
            if EntityCategoryContains(cat.category, u) then
                if not cat.units then
                    cat.units = {}
                end
                table.insert(cat.units,u)
                continue
            end
        end
    end

    local FormationPos = {}

    #LOG('*FORMATION DEBUG: width=' .. width .. ', height=' .. length )

    local side = 1
    local count = 1
    local len = 0

    function BlockLayout(cat)
        count = 1 # parent scope counter
        local n = table.getn(cat.units)
        local width = math.min(20,n*cat.width)
        for k,v in cat.units do

            if count > width then
                count = 1
                side = 1
                len = len + cat.length
            end

            table.insert(FormationPos, { (count-1) * side, -len, cat.category, 0, true })

            if side == 1 then
                count = count + cat.width
            end
            side = -side
        end
        len = len + cat.length
    end

    for k,v in layout do
        if v.units then
            if v.resetPosition then
                len = 0
                side = 1
            end
            BlockLayout(v)
        end
    end

    return FormationPos
end


function VFormation( formationUnits )
    local rotate = true
    local smallUnitsList = {}
    local FormationPos = {}
    local side = 1

    for i in formationUnits do
        local offsetX = math.ceil( ( i - 1 ) / 2 ) * side
        local offsetY = math.ceil( ( i - 1 ) / 2 )
        side = -side
        local delay = 0.1
        table.insert(FormationPos, { offsetX, -offsetY, categories.ALLUNITS, delay, rotate })
    end

    #LOG("*DEBUG: FORMATION: ", repr(FormationPos))

    return FormationPos
end

# local function for performing lerp
local function lerp( alpha, a, b )
    return a + ((b-a) * alpha)
end

function CircleFormation( formationUnits )
    local rotate = false
    local FormationPos = {}
    local numUnits = table.getn(formationUnits)
    local sizeMult = 2.0 + math.max(1.0, numUnits / 3.0)

    # make circle around center point
    for i in formationUnits do
        offsetX = sizeMult * math.sin( lerp( i/numUnits, 0.0, math.pi * 2.0 ) )
        offsetY = sizeMult * math.cos( lerp( i/numUnits, 0.0, math.pi * 2.0 ) )
        table.insert(FormationPos, { offsetX, offsetY, categories.ALLUNITS, 0, rotate })
    end

    return FormationPos
end

function GuardFormation( formationUnits )
    local rotate = false
    local FormationPos = {}
    local numUnits = table.getn(formationUnits)

    local naval = false
    local sizeMult = 3
    for k,v in formationUnits do
        if not v:IsDead() and EntityCategoryContains( categories.MOBILE, v ) then
            naval = true
            sizeMult = 8
            break
        end
    end

    local ringChange = 5
    local unitCount = 1

    # make circle around center point
    for i in formationUnits do
        if unitCount == ringChange then
            ringChange = ringChange + 5
            if naval then
                sizeMult = sizeMult + 8
            else
                sizeMult = sizeMult + 3
            end
            unitCount = 1
        end
        offsetX = sizeMult * math.sin( lerp( unitCount/ringChange, 0.0, math.pi * 2.0 )) # + math.pi / 16 )
        offsetY = sizeMult * math.cos( lerp( unitCount/ringChange, 0.0, math.pi * 2.0 )) # + math.pi / 16 )
        #LOG('*FORMATION DEBUG: X=' .. offsetX .. ', Y=' .. offsetY )
        table.insert(FormationPos, { offsetX - 10, offsetY, categories.ALLUNITS, 0, rotate })
        unitCount = unitCount + 1
    end

    return FormationPos
end